package chatsystem.ni;

import chatsystem.FileTransferStatusCB;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;

/** Ce thread s'occupe de la réception synchrone d'un fichier sur TCP. */
public class FileReceiver extends Thread
{
   /** Les connexions de personnes autres que 'expectedPeer' seront rejetées. */
   public FileReceiver(ChatNI owner, InetAddress expectedPeer, String filename)
   {
      _owner = owner;
      _peer = expectedPeer;
      _name = filename;
      _cancelled = false;
      _signaled = false;
   }
   
   public InetAddress getExpectedAddr()      {return _peer;}
   public String getFileName()               {return _name;}
   
   public void start(FileTransferStatusCB cb)
   {
      _cb = cb;
      super.start();
   }
   
   /** Si annulation AVANT le début du transfert. */
   public void cancel()
   {
      _cancelled = true;
      start();
   }

   /** Annulation en cours de transfert. */
   public void stopRecv()
   {
      // must get sure to stop it even if the stop() slips between the accept()
      // and _sock affectation.
      _cancelled = true;
      closeSock();
   }
   
   public void run()
   {  
      OutputStream file = null;
      try {
         if (_cancelled)
            return;
         
         // TODO let user choose where the file is saved.
         file = new FileOutputStream(_name);
         
         _srvSock = new ServerSocket(16050);
         
         // ignore 'parasite' connections. Should also use source port for this
         // check, but we would need to control the client's code.
         do { 
            _sock = _srvSock.accept();
            if (_cancelled)
               return;
         } while (!_sock.getInetAddress().equals(_peer));
         
         _cb.onStart();
         
         int c;
         InputStream s = _sock.getInputStream();
         
         // Mauvaises perf. Faudrait déplacer des blocs de 4Ko, ou utiliser les 
         // BufferedReader/Writer.
         while ((c = s.read()) != -1)
            file.write(c);
         
         System.out.println("clean finish");
         _cb.onFinish();
         _signaled = true;
      } 
      catch (IOException ex) {
         _cb.onError("Network/IO error");
         _signaled = true;
      }
      finally {
         closeSock();
         if (file != null)
            try {file.close();} catch (IOException e) {}
         if (!_signaled)
            _cb.onError("Cancelled");
         _owner.onFileRecvEnd();
      }
   }
   
   private void closeSock()
   {
      try {
         if (_srvSock != null)
            _srvSock.close();
         if (_sock != null)
            _sock.close();
      } catch (IOException e) {}
   }
   
   private ChatNI _owner;
   private FileTransferStatusCB _cb;
   private InetAddress _peer;
   private String _name;
   private boolean _cancelled;
   private boolean _signaled; // true if CB was called.
   private ServerSocket _srvSock;
   private java.net.Socket _sock;
}
